﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ComputerArchitecture.Core;
using ComputerArchitecture.Core.Logging;
using ComputerArchitecture.Numbers;
using ComputerArchitecture.Units.Integers.Signed.Interfaces;

namespace ComputerArchitecture.Units.Integers.Signed.Implementations
{
    public class SignedAdderUnit : LoggingObject, ISignedAdderUnit
    {
        #region Constructors

        public SignedAdderUnit(ILoggingService loggingService) : base(loggingService)
        {
        }

        #endregion

        #region Methods

        IBitNumber IAdderUnit.Add(IBitNumber first, IBitNumber second, out bool overflow)
        {
            return this.Add((ISignedBitNumber) first, (ISignedBitNumber) second, out overflow);
        }

        public ISignedBitNumber Add(ISignedBitNumber first, ISignedBitNumber second, out bool overflow)
        {
            ArgumentValidator.NullValidate(first);
            ArgumentValidator.NullValidate(second);
            if (first.Size != second.Size)
            {
                throw new ArgumentException();
            }
            this.LoggingService.LogInfo(string.Format("First number: {0:d4}", first));
            this.LoggingService.LogInfo(string.Format("Second number: {0:d4}", second));
            ISignedBitNumber result = new SignedBitNumber(first.Size);
            Bit carryBit = Bit.Zero;
            for (int i = first.Size - 1, j = 1; i >= 0; i--, j++)
            {
                result[i] = FullAdder.Add(first[i], second[i], carryBit, out carryBit);
                this.LoggingService.LogInfo(string.Format("Iteration {0}: result {1:d4}", j, result));
            }
            // if (all zeros and 1 overflow - ignore)
            // if carry from sign - ignore
            if (first.Sign == second.Sign)
            {
                overflow = first.Sign != result.Sign;
            }
            else
            {
                overflow = false;
            }

            return result;
        }

        public ISignedBitNumber Inc(ISignedBitNumber first, out bool overflow)
        {
            /*
            ISignedBitNumber one = SignedBitNumber.GetOne(first.Size);
            return this.Add(first, one, out overflow);
            */
            ArgumentValidator.NullValidate(first);
            ISignedBitNumber result = new SignedBitNumber(first.Size);
            Bit carryBit = Bit.One, firstSign = (Bit) first.SignBit.Clone();
            for (int i = first.Size - 1, j = 1; i >= 0; i--, j++)
            {
                result[i] = FullAdder.Add(first[i], Bit.Zero, carryBit, out carryBit);
            }
            // if (all zeros and 1 overflow - ignore)
            // if carry from sign - ignore
            if (Equals(first.SignBit, firstSign))
            {
                overflow = first.Sign != result.Sign;
            }
            else
            {
                overflow = false;
            }
            return result;
        }

        #endregion
    }
}
